from enum import Enum


class GobangError(Exception):
    '五子棋相关异常'

    def __init__(self, error_msg) -> None:
        self.error_msg = error_msg

    def __str__(self) -> str:
        return repr(self.error_msg)


class ChessColor(Enum):
    WHITE = 'WHITE'
    BLACK = 'BLACK'


class ChessBoard:

    def __init__(self, length=19, width=19) -> None:
        self.length = length
        self.width = width
        self.chesses = [[None for i in range(self.width)] for i in range(self.length)]
        self.winner = None

    def mark(self, x, y, color=ChessColor.BLACK):
        if self.winner is not None:
            raise GobangError('胜负已分')

        if not self.__is_in_board(x, y):
            raise GobangError("不在棋盘范围内")

        if self.chesses[x][y] is not None:
            raise GobangError('该位置已被占用')

        self.chesses[x][y] = color

        if self.__check_win(x, y):
            self.winner = color

        return self.winner

    def __check_win(self, x, y):
        color = self.chesses[x][y]

        # 右
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x + i, y) and self.chesses[x + i][y] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        # 左
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x - i, y) and self.chesses[x - i][y] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        # 上
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x, y + i) and self.chesses[x][y + i] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        # 下
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x, y - i) and self.chesses[x][y - i] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        # 左上
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x - i, y + i) and self.chesses[x - i][y + i] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        # 右上
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x + i, y + i) and self.chesses[x + i][y + i] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        # 左下
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x - i, y - i) and self.chesses[x - i][y - i] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        # 右下
        num = 1
        for i in range(1, 5):
            if self.__is_in_board(x + i, y - i) and self.chesses[x + i][y - i] == color:
                num += 1
            else:
                break
        if num == 5:
            return True

        return False

    def __is_in_board(self, x, y):
        '判断位置坐标是否在棋盘内'
        return x in range(0, self.length) and y in range(0, self.width)
